home *** CD-ROM | disk | FTP | other *** search
- {*********************************************************}
- {* AAHpDeFr *}
- {* Copyright (c) Julian M Bucknall 2000 *}
- {* All rights reserved. *}
- {*********************************************************}
- {* Algorithms Alfresco: Defragmenting heap *}
- {*********************************************************}
-
- {Note: this unit is released as freeware. In other words, you are free
- to use this unit in your own applications, however I retain all
- copyright to the code. JMB}
-
- unit AAHpDeFr;
-
- {WARNING: this unit *must* appear first in your project's uses list.}
-
- interface
-
- implementation
-
- uses
- Windows; // it's OK to use the Windows unit: it allocates no memory
-
- type
- PFreeNode = ^TFreeNode;
- TFreeNode = packed record
- fnNext : PFreeNode;
- end;
-
- const
- MinFreeInx = 0;
- MaxFreeInx = (4096 div 32) - 1;
-
- var
- OrigHeap : TMemoryManager;
- OurHeap : TMemoryManager;
-
- {the free lists for blocks of size 32 to 4096}
- FreeList : array [MinFreeInx..MaxFreeInx] of pointer;
-
- function OurGetMem(Size : integer) : pointer;
- var
- Inx : integer;
- begin
- {make a decision based on the size: if it's less than or equal to
- 4096 we can get the allocation from our free lists...}
- if (Size <= 4096) then begin
- {round up to the nearest 32 bytes}
- Size := (Size + 31) and not integer(31);
- {if there is a node free on the relevant free list, use it}
- Inx := pred(Size div 32);
- if (FreeList[Inx] <> nil) then begin
- Result := FreeList[Inx];
- FreeList[Inx] := PFreeNode(Result)^.fnNext;
- end
- {otherwise allocate from Delphi's heap manager}
- else
- Result := OrigHeap.GetMem(Size);
- end
- {otherwise the size is too great for our linked lists, round up to
- nearest 1KB and then allocate it from Delphi's heap manager}
- else begin
- Size := (Size + 1023) and not integer(1023);
- Result := OrigHeap.GetMem(Size);
- end;
- end;
-
- function OurFreeMem(P : pointer) : integer;
- type
- PInteger = ^integer;
- var
- Size : integer;
- Inx : integer;
- begin
- {make a decision based on the block's size: if it's less than or
- equal to 4096 we can store it on our free lists...}
- Size := PInteger(PChar(P) - sizeof(integer))^ - sizeof(integer);
- if (Size <= 4096) then begin
- Inx := pred(Size div 32);
- PFreeNode(P)^.fnNext := FreeList[Inx];
- FreeList[Inx] := PFreeNode(P);
- Result := 0; {no error}
- end
- {otherwise just free it with the original heap manager}
- else
- Result := OrigHeap.FreeMem(P);
- end;
-
- function OurReallocMem(P : pointer; Size : integer) : pointer;
- var
- OldSize : integer;
- begin
- {Realloc is complicated: we need to trap reallocations using our
- free lists. Realloc can be called with 4 possibilities:
- P = nil, Size = 0: return nil
- P = nil, Size > 0: equivalent to GetMem(Size), return new block
- P <> nil, Size = 0: equivalent to FreeMem(Size), return nil
- P <> nil, Size > 0: equivalent to GetMem(Size), copy old data to
- new block, FreeMem(P), return new block}
- if (P = nil) then begin
- if (Size <> 0) then
- Result := OurGetMem(Size)
- else
- Result := nil;
- end
- else begin
- if (Size = 0) then begin
- OurFreeMem(P);
- Result := nil;
- end
- else begin
- Result := OurGetMem(Size);
- OldSize := PInteger(PChar(P) - sizeof(integer))^ - sizeof(integer);
- if (OldSize <= Size) then
- Move(P^, Result^, OldSize)
- else
- Move(P^, Result^, Size);
- OurFreeMem(P);
- end;
- end;
- end;
-
- procedure InitializeUnit;
- begin
- {initialize the freelists}
- FillChar(FreeList, sizeof(FreeList), 0);
-
- {get the original manager}
- GetMemoryManager(OrigHeap);
-
- {set up our heap manager}
- OurHeap.GetMem := OurGetMem;
- OurHeap.FreeMem := OurFreeMem;
- OurHeap.ReallocMem := OurReallocMem;
-
- {replace heap manager with ours}
- SetMemoryManager(OurHeap);
- end;
-
- procedure FinalizeUnit;
- var
- i : integer;
- P : PFreeNode;
- Temp : PFreeNode;
- begin
- {free all blocks on the free lists}
- for i := MinFreeInx to MaxFreeInx do begin
- P := FreeList[i];
- while (P <> nil) do begin
- Temp := P;
- P := P^.fnNext;
- OrigHeap.FreeMem(Temp);
- end;
- end;
- {restore the original manager}
- SetMemoryManager(OrigHeap);
- end;
-
- initialization
- InitializeUnit;
-
- finalization
- FinalizeUnit;
-
- end.
-